iT邦幫忙

2024 iThome 鐵人賽

DAY 23
0
生成式 AI

T 大使 AI 之旅系列 第 23

【Day 23】調教你的 AI 寵物:用微調讓 LLM 乖乖聽話

  • 分享至 

  • xImage
  •  

前情提要

上一篇文章我們了解了資料集的結構和如何設計,也了解了 FineTune 用到的 LoRA 的技術 (背後的數學和理論就不提了)。還有看了很多不同的微調框架,也有提到 OpenAI 和 Mistral 有自己家的 FineTune,還有台智雲的 No-Code 微調,所以今天就一一來程式實作吧!
https://ithelp.ithome.com.tw/upload/images/20240828/20168336hzQOJqBmwX.png

Alpaca 資料集

昨天只有提到這個資料集被廣泛拿來作為微調模型的資料,那我們要客製化自己的資料集,就必須跟著 Alpaca 的結構來建立資料集。

  • mhenrichsen/alpaca_2k_test
    https://ithelp.ithome.com.tw/upload/images/20240827/201683369GjD2xKVXy.png
    上圖就是 Alpaca 資料集的結構,可以看到總共有四個欄位,那我們分別來看看要怎麼設計。
  • instruction:instruction 這個欄位主要就是放入你要輸入給模型的內容,這個內容可能是一個問題、可能是一個任務,算是 user 最主要輸入內容的部分。
  • input:input 這個欄位可以是空值,要與 instruction 做搭配。我自己的認知是,如果今天 instruction 是個問題,那麼通常 input 就會是空的;但是如果今天 instruction 是一個任務,那麼 input 就會有輸入,但其實也沒有一定,還是要回到本身任務來依據狀況適當填入。
    • 從上圖的舉例來說,可以看到有指派任務是解方程式還有算中位數之類的,這些你就要在 input 給一個方程式或給一串數列。那其他沒有 input 給 AI 的任務是設計一個 logo 啊,或者是寫一首詩等等,所以還是要根據情況來判斷 input 要不要填入~
  • output:output 就很簡單是希望 AI 回傳的內容。
  • text:就是在 instruction 前面會再給一串 prompt,通常是要 AI 根據 instruction 指令來完成特定任務,然後把 instruction、input、output 連在一起。所以在微調模型完,要測試的時候可以使用 text 來看看微調的成效如何。

開源微調框架實戰🔥

這邊要實作的是昨天有提到的三個框架,分別是 AxolotlUnslothLlamaFactory。那我的執行環境都會是 Colab,只需要免費的 T4 GPU 即可運行,因為他們都只支援 CUDA (可能 Mac 可以是我不會操作)。然後這邊的數據集都會使用 Alpaca 資料或者遵循他的結構來客製化資料。

Axolotl

Axolotl 在他們 GitHub 有提供 Colab 程式碼,但是我自己測試什麼都沒改是沒辦法跑成功,所以經過了一些修正可以順利執行,但是使用 gradio 測試的部分我是不行,所以我是將模型上傳到 HuggingFace 再來測試。

  1. 安裝套件以及 Axolotl 整個資料夾的資料
!git clone -q https://github.com/OpenAccess-AI-Collective/axolotl
%cd axolotl
!pip install -qqq packaging huggingface_hub --progress-bar off
!pip install -qqq -e '.[flash-attn,deepspeed]' --progress-bar off
!pip install mlflow
  1. 設定微調參數 yaml 檔
import yaml

yaml_string = """
base_model: TinyLlama/TinyLlama-1.1B-intermediate-step-1431k-3T
model_type: LlamaForCausalLM
tokenizer_type: LlamaTokenizer
is_llama_derived_model: true

load_in_8bit: false
load_in_4bit: true
strict: false

datasets:
	- path: mhenrichsen/alpaca_2k_test
	type: alpaca
dataset_prepared_path:
val_set_size: 0.05
output_dir: ./qlora-out

adapter: qlora
lora_model_dir:
sequence_len: 1096
sample_packing: true
pad_to_sequence_len: true

lora_r: 32
lora_alpha: 16
lora_dropout: 0.05
lora_target_modules:
lora_target_linear: true
lora_fan_in_fan_out:

wandb_project:
wandb_entity:
wandb_watch:
wandb_name:
wandb_log_model:

mlflow_experiment_name: colab-example

gradient_accumulation_steps: 1
micro_batch_size: 1
num_epochs: 4
max_steps: 20
optimizer: paged_adamw_32bit
lr_scheduler: cosine
learning_rate: 0.0002

train_on_inputs: false
group_by_length: false
bf16: false
fp16: true
tf32: false

gradient_checkpointing: true
early_stopping_patience:
resume_from_checkpoint:
local_rank:
logging_steps: 1
xformers_attention:
flash_attention: false

warmup_steps: 10
evals_per_epoch:
saves_per_epoch:
debug:
deepspeed:
weight_decay: 0.0
fsdp:
fsdp_config:
special_tokens:
"""

# 將以上 yaml 檔內容放入 Python 變數
yaml_dict = yaml.safe_load(yaml_string)

# 指定 yaml 檔名詞
yaml_file = 'config.yaml'

# 寫入 ymal 檔
with open(yaml_file, 'w') as file:
	yaml.dump(yaml_dict, file)
  1. 讀取 yaml 檔開始訓練模型
!accelerate launch -m axolotl.cli.train config.yaml
  1. 訓練完成後,可以透過此指令打開 gradio 測試介面,但我自己測試是不成功
!accelerate launch -m axolotl.cli.inference config.yaml --qlora_model_dir="./qlora-out" --gradio
  1. 將 LoRA 模型與主模型進行合併
!python3 -m axolotl.cli.merge_lora config.yaml --lora_model_dir="./qlora-out"
  1. 登入 HuggingFace 並將前面合併的模型上傳到 HuggingFace
from huggingface_hub import HfApi
from google.colab import userdata

new_model = "Your Model"

api = HfApi(token="hf_token")

# Upload merge folder
api.create_repo(
	repo_id=new_model,
	repo_type="model",
	exist_ok=True,
)

api.upload_folder(
	repo_id=new_model,
	folder_path="qlora-out/merged",
)
  1. 調用模型
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer

model_name = "Your Model"
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForCausalLM.from_pretrained(model_name)

device = torch.device("cuda")
model.to(device)
input_text = """Below is an instruction that describes a task, paired with an input that provides further context. Write a response that appropriately completes the request.

### Instruction: What is the capital of France?
### Input:
### Response:"""

input_ids = tokenizer.encode(input_text, return_tensors="pt").to(device)
output_ids = model.generate(input_ids, max_length=100)

output_text = tokenizer.decode(output_ids[0], skip_special_tokens=True)
print(output_text)

https://ithelp.ithome.com.tw/upload/images/20240827/20168336tmA8vG2Y8e.png
程式碼結果探討 🧐:

  • 因為 axolotl 訓練的有點久,然後常常調一些參數就 error,其他兩個框架不會,所以我就以最簡單最快速的方式來實作。
  • 可能是我能力還沒到也受限於硬體限制,所以沒有太顯著的效果。

LLaMA-Factory

LLaMA-Factory 在他們 GitHub 有提供 Colab 程式碼,但我自己覺得是相對友善的,因為他的 Fine Tune 不需要寫程式。他的程式碼就是一路執行下去直到開啟 gradio 的頁面,就可以開始 Fine Tune 了。

  1. 進入以下頁面選擇模型和訓練資料集,並且設定參數,紅色框框是我在使用會比較優先調整的部分。簡單介紹一些比較常調整的參數:
    • Finetuning method:受限於硬體所以基本上就是選擇 LoRA,但他也支援 Full 完整微調。
    • Quantization Bit:受限於硬體所以會選擇 4-bit8-bit 量化,可以減少模型的內存佔用和推理時間,但可能會影響模型性能。
    • Quantization method:bitsandbytes 是用來優化模型的內存使用和計算效率,可以大幅減少模型參數的佔用空間,特別適合在資源有限的情況下進行訓練。
    • Learning Rate:這個沒有一定的數值,要根據模型訓練的結果來逐步調整。
    • Epochs:Epochs 決定了模型看到完整數據集的次數。較多的週期通常可以讓模型學習得更好,但也增加了 over-fitting 的風險。
    • Batch Size:每次模型更新時處理的樣本數量,通常是大一點好,可以使梯度估計更加準確,通常收斂更加穩定。但是也較吃 GPU 效能,因為需要更多的運算。
    • Gradient Accumulation:在 GPU 記憶體有限的情況下使用。通過累積多次的小 batch size 的梯度來更新模型參數,可以達到與大 Batch Size 相似的效果。
    • Max Samples:有時候可能不需要使用整個數據集來訓練模型,或者你可能只想利用數據集的一部分來快速驗證模型的性能,設定這個可以用來提前停止訓練過程。
      https://ithelp.ithome.com.tw/upload/images/20240827/20168336pV7u2UmJDZ.png
  2. 設定完成後可以預覽訓練參數的 yaml 檔,其實就是跟 axolotl 的 yaml 檔是一樣的設置,只是 LLaMA Factory 不需要自己刻,算是很佛心。確定沒問題後就可以開始進行訓練了!
    https://ithelp.ithome.com.tw/upload/images/20240827/20168336P2kmgvRwIN.png
  3. 訓練完之後就要來使用模型啦~但我必須說真的是訓練超級久,我想說玩看看然後把參數都調很小,還是等了大約 20 分鐘。要使用訓練好的模型在 checkpoint path 的地方選擇剛剛訓練完的模型名稱,然後選擇 Load Model,然後載入完成就可以開始使用了!
    https://ithelp.ithome.com.tw/upload/images/20240827/201683369SSij1nepk.png
  4. 最後也是簡單玩一下模型,但少參數和少量的訓練真的效果很差哈哈哈,但是不需要動手寫程式是不錯的選擇~
    https://ithelp.ithome.com.tw/upload/images/20240827/20168336eB29SDH31M.png
  5. 若是要使用自己的資料進行微調,可以到他的 Data 資料夾中上傳檔案,除了 Alpaca 資料型態以外,也有支援很多其他的資料型態,有興趣的可以研究研究~

Unsloth

再來就要分享我覺得是目前最好用的 Colab 微調框架,而且他真的速度很快,微調效果也好,就來實作看看!

  1. 首先要先準備一個 Alpaca 資料型態的數據集,然後存成 Json 檔,可以上傳 HuggingFace 也可以直接以 Json 檔拿去微調。
[
	{
		"instruction": "2024年巴黎奧運男子100米短跑的金牌得主是誰?",
		"input": "",
		"output": "2024年巴黎奧運男子100米短跑的金牌得主是美國的 Noah Lyles。"
	},
	{
		"instruction": "2024年巴黎奧運女子舉重59公斤級,中華隊郭婞淳成績?",
		"input": "",
		"output": "2024年巴黎奧運女子舉重59公斤級的台灣的郭婞淳傷癒復出征戰奧運奪下銅牌。"
	},
	{
		"instruction": "2024年巴黎奧運羽毛球男子單打的金牌得主是誰?",
		"input": "",
		"output": "2024年巴黎奧運羽毛球男子單打的金牌得主是丹麥的維克托·阿薩爾森(Viktor Axelsen)。"
	},
	{
		"instruction": "台灣在2024年巴黎奧運拳擊女子57公斤比賽中獲得了什麼獎牌?",
		"input": "",
		"output": "台灣在2024年巴黎奧運拳擊女子57公斤比賽中林郁婷獲得了金牌。"
	},
	{
		"instruction": "2024年巴黎奧運男子籃球比賽的金牌得主是誰?",
		"input": "",
		"output": "2024年巴黎奧運男子籃球比賽的金牌得主是美國隊,由 LeBron James 拿下最後的奧運 MVP。"
	},
	{
		"instruction": "台灣在2024年巴黎奧運羽毛球男子雙打比賽中獲得了什麼獎牌?",
		"input": "",
		"output": "台灣在2024年巴黎奧運羽毛球男子雙打比賽中獲得了金牌,由王齊麟和李洋搭檔獲得。"
	}
]
  1. 資料集上傳 HuggingFace -> SeanNChen/ithome-2024-alpaca
# !pip install datasets
# !pip install huggingface_hub

from huggingface_hub import login
from datasets import Dataset
login()

import json
with open("ithome_unsloth.json", "r") as f:
	data = json.load(f)

formatted_data = {
	"instruction": [item['instruction'] for item in data],
	"input": [item['input'] for item in data],
	"output": [item['output'] for item in data]
}

dataset = Dataset.from_dict(formatted_data)
dataset.push_to_hub("SeanNChen/ithome-2024-alpaca")
  1. 接下來到 Unsloth 的 GitHub 找到要 FineTune 的模型,我這邊選擇最近剛發表的 llama 3.1 來進行模型微調 (若要微調別的模型要注意其他模型的資料型態喔~像最新的 phi 3.5 就不是使用 Alpaca 資料集的型態)。
    https://ithelp.ithome.com.tw/upload/images/20240827/20168336jgBMQGV398.png
  2. 那我們需要調整和加入一些的程式碼:
    1. 找到 Data Prep 的那個 Block,將其改成 HuggingFace 的路徑,或者是自己建立一個資料夾,然後將 Json 檔上傳至資料夾
      https://ithelp.ithome.com.tw/upload/images/20240827/20168336pBJbair5uf.jpg
    2. 接著找到 GGUF 的那個 Block,這是用來設定要如何儲存微調好的模型。我們將參數最小的 "q4_k_m" 修改成 True,一樣以最簡單的方式來訓練模型,Unsloth 也很貼心的解釋 q4、q5、q8 的差異。
      https://ithelp.ithome.com.tw/upload/images/20240827/20168336YRRcWamdnY.png
    3. 若要上傳至 HuggingFace 的話, 就將想要儲存的模型前面改成 True 並輸入 HuggingFace Token 即可喔!
      https://ithelp.ithome.com.tw/upload/images/20240827/20168336RIgmDKzQGX.png
    4. 接著將模型複製儲存到 Google Drive 再下載下來速度會比較快,加入以下程式碼即可。
from google.colab import drive
drive.mount('/content/drive')

import shutil
local = '/content/model-unsloth.Q4_K_M.gguf'
google_drive = '/content/drive/My Drive/model-unsloth.Q4_K_M.gguf'
shutil.copy(local, google_drive)
  1. 接著就可以開始進行模型微調啦~如果資料量大的話要記得修改 TrainingArguments 中的參數喔,要多訓練幾輪才會有較好的效果。看到以下結果就是訓練成功啦,然後我這個資料集非常簡單所以很快而且 loss 很低的被成功訓練了。
    https://ithelp.ithome.com.tw/upload/images/20240827/20168336vda32Zzprf.png
  2. 輸出成 gguf 檔的模型會比較久一點,好了之後將 gguf 檔從雲端下載到本機就可以使用了!上傳到 HuggingFace 的模型也可以使用,就像一般正常使用 HuggingFace 的模型一樣。
  3. 下載 gguf 檔之後,我們要將模型上傳到 Ollama。路徑:設定 -> 管理員控制台 -> 模型,可以在網頁上看到上傳 GGUF 的地方,接著就開始上傳剛剛的 GGUF 檔。
    https://ithelp.ithome.com.tw/upload/images/20240828/20168336ILMD7Pi9V7.png
  4. 模型測試 - Ollama gguf 結果展示
    https://ithelp.ithome.com.tw/upload/images/20240828/20168336ZuJMDzXLBQ.png
    程式碼結果探討 🧐:
  • 不管是 HuggingFace 還是使用 GGUF 可以看到針對微調的內容模型都能回答出來,這就是微調的效果,讓模型在既有知識上再去學習新東西。

Mistral

在 Mistral 他們 GitHub 有提供 Colab 程式碼,他們的資料集就不是使用 Alpaca 的資料型態,但他們程式碼中有展示他們範例的資料型態,我們在用 LangChain 的 ChatPromptTemplate 很像。那我自己是有換成自己的資料集測試,結果是一路都可以很順的執行,模型訓練的速度也很快,但是在最後要測試模型訓練效果的時候,他顯示爆 RAM 了,所以沒辦法使用,因此沒有測試結果。如果大家有用 Mistral 自家的 FineTune 程式訓練測試成功 Mistral 模型的的話,歡迎跟我分享喔~

OpenAI

我目前是還沒使用過 OpenAI 的 FineTune,但作為目前最強 AI,如果能 FineTune 那應該效果不會太差。在 OpenAI 官網 有很明確的介紹了如何 FineTune OpenAI 的模型,也有表示要使用哪種資料型態。我同事有 FineTune 過 gpt-3.5,但我們推測是樣本數太少導致學習效果不好。如果大家有 FineTune 過 OpenAI 的話歡迎跟我分享喔~

結論

我們今天實作了目前開源的三個框架,其實各有好壞,或許有本機 GPU 的人不會選擇 Unsloth 架構。但我覺得在資源有限的情況下,Unsloth 是最適合初學者也最省時的。微調 LLM 是一個既有挑戰又充滿可能性的過程。選擇合適的工具、設計好資料集,並適時進行實驗和調整,能夠顯著提升模型的應用效果。

題外話🤣

最近被通知入伍時間了,要準備去當兵了~看來離社畜人生又更進了一步😆

下一篇文章:Agent 入門指南:從零開始構建智能代理


上一篇
【Day 22】什麼是模型微調,能吃嗎?
下一篇
【Day 24】Agent 入門指南:從零開始構建智能代理
系列文
T 大使 AI 之旅30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言